package game.mapa;

import game.entidades.Elemento;
import game.entidades.ElementosFactory;
import game.entidades.NaveInimiga;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Classe que controla o mapa representado por um txt, instancia os elementos pertencentes ao jogo
 * dependendo se sua posição no mapa e o caracter que o representa.
 * Tambem contem uma lista de todos os objetos animados que estao atualmente aparecendo na tela, os atualiza
 * e desenha.
 * @author LeandroBeni e DeboraGonçalves
 */
public class ControladorDoMapa {

    private Image imagens[];
    private Image texturas[];
    private float posicao;
    private float velocidade;
    private Mapa mapa;

    /**
     * Construtor que inicializa o controlador do mapa.
     */
    public ControladorDoMapa() {
        this.imagens = new Image[2];
        this.texturas = new Image[1];
        this.posicao = 0;
        this.velocidade = (float) 0.05;
    }

    /**
     * Carrega todas as figuras que o jogo utiliza para a memoria, separando e colocando em um vetor de textura
     * e outro de imagens de personagens animados
     */
    public void carregaImagens() {

        for (int i = 0; i < this.imagens.length; i++) {
            String filename = "/imagens/elementos/" + i + ".gif";
            URL url = ControladorDoMapa.class.getResource(filename);
            imagens[i] = Toolkit.getDefaultToolkit().getImage(url);
            imagens[i] = imagens[i].getScaledInstance(64, 64, Image.SCALE_DEFAULT);
        }

        for (int i = 0; i < this.texturas.length; i++) {
            String filename = "/imagens/elementos/1.gif";
            URL url = ControladorDoMapa.class.getResource(filename);
            imagens[i] = Toolkit.getDefaultToolkit().getImage(url);
            imagens[i] = imagens[i].getScaledInstance(64, 64, Image.SCALE_DEFAULT);
        }
    }

    /**
     * Le um arquivo txt e carrega ele como mapa em um objeto mapa.
     * @param name nome do mapa que deseja carregar.
     * @throws IOException
     */
    public void carregaMapa(int name) throws IOException {

        String filename = "/mapas/" + name + ".txt";
        ArrayList<String> linhas = new ArrayList<String>();

        int altura = 0;
        int largura = 0;
        BufferedReader reader;

        reader = new BufferedReader(new InputStreamReader(
                getClass().getResourceAsStream(filename)));

        while (true) {
            String linha = reader.readLine();
            // sem mais linhas para ler
            if (linha == null) {
                reader.close();
                break;
            }

            // adiciona toda linha menos os comentários
            if (!linha.startsWith("#")) {
                linhas.add(linha);
                largura = Math.max(largura, linha.length());
            }
        }

        // parseia as linhas para criar uma TileEngine
        altura = linhas.size();
        Mapa novoMap = new Mapa(altura, largura);

        for (int y = 0; y < altura; y++) {

            String line = (String) linhas.get(y);
            for (int x = 0; x < line.length(); x++) {
                char ch = line.charAt(x);

                //verifica se o caracter represente uma textura do jogo
                for (int i = 0; i < texturas.length; i++) {
                    if (ch == (char) i) {
                        novoMap.setPosicao(y, x, texturas[i]);
                        break;
                    }
                }

                //verifica se o caracter representa um elemento do jogo
                char c = 'a';
                for (int i = 0; i < imagens.length; i++) {
                    if (ch == c) {
                        novoMap.setPosicao(y, x, imagens[i]);
                        break;
                    }
                    c++;
                }
            }
        }

        this.mapa = novoMap;
    }

    /**
     * Localiza no mapa a posição da tela e instancia os elementos ainda nao instanciados.
     */
    public void localizaPosicaoTela() {

        int posEmFigura = (int) ControladorDoMapa.pixelsParaFiguras(posicao);

        for (int i = posEmFigura; i < posEmFigura + 20; i++) {
            for (int j = 0; j < mapa.getNumColuna(); j++) {
                if (mapa.getPosicao(i, j) != null) {
                    if (mapa.getPosicao(i, j) == this.imagens[0]) {
                        NaveInimiga inimigo = ElementosFactory.instanciaInimigo(this.imagens[0],
                                figuraParaPixels(j), 0, (float) 0.06, (float) 0.10, 1);
                        mapa.addElemento(inimigo);
                        mapa.setPosicao(i, j, null);//tira a imagem da matriz
                    } else if (mapa.getPosicao(i, j) == this.imagens[1]) {
                        NaveInimiga inimigo = ElementosFactory.instanciaInimigo(this.imagens[0],
                                figuraParaPixels(j), 0, (float) 0.06, (float) 0.10, 2);
                        mapa.addElemento(inimigo);
                        mapa.setPosicao(i, j, null);//tira a imagem da matriz
                    } else if (mapa.getPosicao(i, j) == this.imagens[2]) {
                        //pega instancia de um objeto desse com essa imagem
                        //adiciona na lista
                        //seta imagem da matriz como null
                    } else if (mapa.getPosicao(i, j) == this.imagens[3]) {
                        //pega instancia de um objeto desse com essa imagem
                        //adiciona na lista
                        //seta imagem da matriz como null
                    }
                }

            }
        }


    }

    /**
     * Chama o metodo de conversao de coordenada em pixels para imagem,
     * passando como argumento o valor a ser convertido em int( recebe um float
     * e passa pra int).
     * @param pixels pixels a serem convertidos.
     * @return numero em figura que os pixels representam.
     */
    public static int pixelsParaFiguras(float pixels) {
        return pixelsParaFiguras(Math.round(pixels));
    }

    /**
     * Transforma cordenada em pixels para imagens do jogo.
     * @param pixels pixels a serem convertidos.
     * @return numero em figura que os pixels representam.
     */
    public static int pixelsParaFiguras(int pixels) {
        return pixels / 64;
    }

    /**
     * Transforma cordenada em imagem para pixels.
     * @param figura cordenada em imagem a ser convertida.
     * @return pixels que a imagem representa.
     */
    public static float figuraParaPixels(int figura) {
        return figura * 64;
    }

    /**
     * Atualiza todos os elementos que estão na tela do jogo.
     * @param elapsedTime tempo decorrido desde a ultima atualização.
     */
    public void update(long elapsedTime) {

        this.localizaPosicaoTela();

        Iterator<Elemento> i = mapa.getElementos();

        while (i.hasNext()) {
            Elemento elemento = i.next();
            if (elemento instanceof NaveInimiga) {
                NaveInimiga nave = (NaveInimiga) elemento;
                nave.update(elapsedTime);
            }


        }
        this.posicao += elapsedTime * velocidade; //exemplo
    }

    /**
     * Desenha todos os elementos do jogo que estao na tela.
     * @param g
     */
    public void draw(Graphics2D g) {
        Iterator<Elemento> i = mapa.getElementos();
        g.setColor(Color.black);
        g.fillRect(0, 0, 800, 600);
        while (i.hasNext()) {
            Elemento elemento = i.next();
            if (elemento instanceof NaveInimiga) {
                NaveInimiga nave = (NaveInimiga) elemento;
                nave.draw(g);

            }
        }
    }
}
